﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Extentions;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Senparc.Weixin.MP.AdvancedAPIs.OAuth;
using TrainingReminderSystem.Dal;
using TrainingReminderSystem.Model;
using Z.EntityFramework.Plus;

namespace TrainingReminderSystem.Bll
{
    /// <summary>
    /// PC端基础类
    /// </summary>
    public partial class PcLoginedBll : BaseBll
    {
        #region 构造函数

        public PcLoginedBll() : base()
        {
        }

        /// <summary>
        /// 线程内只能调用此构造函数
        /// 多语言调用
        /// </summary>
        /// <param name="sessionID"></param>
        public PcLoginedBll(string sessionID) : base(sessionID)
        {
        }

        #endregion

        #region 登录信息相关

        #region 请求用户Token信息

        /// <summary>
        /// token名称
        /// 全小写是因为有android浏览器的会传入小写
        /// </summary>
        public const string PcTokenKey = "totalwebapitoken";

        /// <summary>
        /// 设备唯一标识
        /// </summary>
        private const string DeviceKey = "device";

        /// <summary>
        /// 获取token字符串
        /// </summary>
        public static string Token
        {
            get
            {
                //Header里面去取,取不到就在cookie里面取
                var c = ExHttpContext.Current;
                if (c == null || c.Request == null) return string.Empty;
                string token = c.Request.Headers[PcTokenKey];
                if (string.IsNullOrEmpty(token))
                {
                    token = c.Request.Cookies[PcTokenKey];
                    if (!string.IsNullOrEmpty(token))
                    {
                        token = System.Web.HttpUtility.UrlDecode(token);
                    }
                }
                return token;
            }
        }

        #endregion

        #region Device唯一请求标识

        /// <summary>
        /// Device唯一请求标识
        /// </summary>
        public static string Device
        {
            get
            {
                var c = ExHttpContext.Current;
                if (c == null || c.Request == null) return string.Empty;
                string device = c.Request.Headers[DeviceKey];
                return device;
            }
        }

        #endregion

        #region 请求用户信息

        /// <summary>
        /// 缓存名字
        /// </summary>
        private const string CacheCurrentEmployee = "CacheCurrentEmployee";

        /// <summary>
        /// 当前员工,绑定了员工的才能登录
        /// </summary>
        public static SysEmployee CurrentEmployee
        {
            get
            {
                var obj = CacheHelper.GetCache(CacheCurrentEmployee + Token) as SysEmployee;
                return obj;
            }
        }

        /// <summary>
        /// 是否能看到手机号
        /// </summary>
        public static bool CanSeePhone
        {
            get
            {
                var current = CurrentEmployee;
                if (current == null) return false;
                return current.CanSeePhone;
            }
        }

        //private const string CacheCurrentRights = "CacheCurrentRights";

        /// <summary>
        /// 当前权限
        /// </summary>
        public static List<SysPower> CurrentRights
        {
            get
            {
                var emp = CurrentEmployee;
                if (emp == null) return null;
                return emp.CurrentRights;
            }
        }

        private const string CacheCurrentRightsUrls = "CacheCurrentRightsUrls";

        /// <summary>
        /// 当前权限的所有路径
        /// </summary>
        public static List<string> CurrentRightsUrls
        {
            get
            {
                var rights = CurrentRights;
                if (rights == null) return new List<string>();
                var obj = CacheHelper.GetCache(CacheCurrentRightsUrls + Token) as List<string>;
                if (obj != null) return obj;
                var list = new List<string>();
                const char splitChat = ',';
                foreach (var item in rights)
                {
                    if (!string.IsNullOrEmpty(item.SysPowerValue))
                    {
                        list.AddRange(item.SysPowerValue.Split(splitChat));
                    }
                    if (!string.IsNullOrEmpty(item.SysPowerValue2))
                    {
                        list.AddRange(item.SysPowerValue2.Split(splitChat));
                    }
                }
                CacheHelper.SetRelativeCache(CacheCurrentRightsUrls + Token, list);
                return list;
            }
        }

        //private const string CacheCurrentStore = "CacheCurrentStore";

        /// <summary>
        /// 当前店铺
        /// </summary>
        public static SysStore CurrentStore
        {
            get
            {
                if (SysConfig.EnumRunProject == EnumRunProject.系统后台端)
                {
                    var emp = CurrentEmployee;
                    if (emp == null) return null;
                    return emp.GetCurrentStore();
                }
                if (SysConfig.EnumRunProject == EnumRunProject.微信客户端)
                {
                    return CustomerLoginedBll.CurrentStore;
                }

                var emp2 = CurrentEmployee;
                if (emp2 == null) return null;
                return emp2.GetCurrentStore();
            }
        }

        /// <summary>
        /// 是否是管理员店铺
        /// </summary>
        public static bool IsAdminStore
        {
            get
            {
                var current = CurrentStore;
                if (current == null) return false;
                var r = current.IsAdminStore();
                return r;
            }
        }

        #region 缓存相关

        protected static void SetCurrentEmployee(string token, SysEmployee obj)
        {
            if (obj != null) obj.Token = token;
            CacheHelper.SetRelativeCache(CacheCurrentEmployee + token, obj);
        }

        //protected static void SetCurrentRights(string token, List<SysPower> obj)
        //{
        //    CacheHelper.SetRelativeCache(CacheCurrentRights + token, obj);
        //    CacheHelper.RemoveCache(CacheCurrentRightsUrls + token);
        //}

        ///// <summary>
        ///// 赋值店铺信息
        ///// </summary>
        ///// <param name="token"></param>
        ///// <param name="store"></param>
        //protected static void SetCurrentStore(string token, SysStore store)
        //{
        //    CacheHelper.SetRelativeCache(CacheCurrentStore + token, store);
        //}

        /// <summary>
        /// 清除缓存
        /// </summary>
        /// <param name="token"></param>
        public static void ClearCache(string token)
        {
            CacheHelper.RemoveCache(CacheCurrentEmployee + token);
            //CacheHelper.RemoveCache(CacheCurrentRights + token);
            CacheHelper.RemoveCache(CacheCurrentRightsUrls + token);
            //CacheHelper.RemoveCache(CacheCurrentStore + token);
        }

        private static object _sync = new object();

        /// <summary>
        /// 清除员工缓存信息
        /// </summary>
        /// <param name="sysEmployeeID"></param>
        protected static void ClearCache(int sysEmployeeID)
        {
            lock (_sync)
            {
                try
                {
                    var list = CacheHelper.GetList(CacheCurrentEmployee + sysEmployeeID + SysEmployeeBll.TokenSplit);
                    foreach (var item in list)
                    {
                        CacheHelper.RemoveCache(item.Key);
                    }
                    //list = CacheHelper.GetList(CacheCurrentStore + sysEmployeeID + SysEmployeeBll.TokenSplit);
                    //foreach (var item in list)
                    //{
                    //    CacheHelper.RemoveCache(item.Key);
                    //}
                    //list = CacheHelper.GetList(CacheCurrentRights + sysEmployeeID + SysEmployeeBll.TokenSplit);
                    //foreach (var item in list)
                    //{
                    //    CacheHelper.RemoveCache(item.Key);
                    //}
                    list = CacheHelper.GetList(CacheCurrentRightsUrls + sysEmployeeID + SysEmployeeBll.TokenSplit);
                    foreach (var item in list)
                    {
                        CacheHelper.RemoveCache(item.Key);
                    }
                }
                catch (Exception ex) { }
            }
        }

        #endregion

        #endregion

        #region 微信登录信息

        #region 微信OpenID信息

        /// <summary>
        /// token名称
        /// 全小写是因为有android浏览器的会传入小写
        /// </summary>
        public const string WechatPcTokenKey = "wechattotalwebapitoken";

        /// <summary>
        /// 获取token字符串
        /// </summary>
        public static string WechatToken
        {
            get
            {
                //Header里面去取,取不到就在cookie里面取
                var c = ExHttpContext.Current;
                if (c == null || c.Request == null) return string.Empty;
                string token = c.Request.Headers[WechatPcTokenKey];
                if (string.IsNullOrEmpty(token))
                {
                    token = c.Request.Cookies[WechatPcTokenKey];
                    if (!string.IsNullOrEmpty(token))
                    {
                        token = System.Web.HttpUtility.UrlDecode(token);
                    }
                }
                return token;
            }
            set
            {
                var c = ExHttpContext.Current;
                if (c == null || c.Request == null) return;
                c.Request.Headers.Remove(WechatPcTokenKey);
                c.Request.Headers.Add(WechatPcTokenKey, value);
            }
        }

        /// <summary>
        /// 缓存名字
        /// </summary>
        private const string CacheSysEmployeeOpenID = "CacheSysEmployeeOpenID";

        /// <summary>
        /// 当前OpenID
        /// </summary>
        public static SysEmployeeOpenID CurrentOpenID
        {
            get
            {
                var obj = CacheHelper.GetCache(CacheSysEmployeeOpenID + WechatToken) as SysEmployeeOpenID;
                return obj;
            }
        }

        /// <summary>
        /// 设置OpenID
        /// </summary>
        /// <param name="wechatToken"></param>
        /// <param name="val"></param>
        protected static void SetCurrentOpenID(string wechatToken, SysEmployeeOpenID val)
        {
            CacheHelper.SetRelativeCache(CacheSysEmployeeOpenID + wechatToken, val);
        }

        #endregion

        #endregion

        #endregion

        #region 数据库访问对象

        /// <summary>
        /// 数据库访问对象
        /// </summary>
        public static DbEntities Db
        {
            get
            {
                DbEntities db = DbEntitiesHelper.GetDbEntities(false);
                var currentStore = CurrentStore;
                if (currentStore != null)
                {
                    //基础表才加
                    int storeID = currentStore.SysStoreID;
                    if (currentStore.IsAdminStore())
                    {
                        //表SysDic全开放,但是查询列表的时候 要带上店铺ID
                        //db.Filter<SysDic>(nameof(SysDic) + nameof(SysStore.SysStoreID),
                        //    m => m.Where(n => n.SysStoreID == storeID));
                        //配置信息表;登录的时候,没有此筛选条件
                        db.Filter<SysSetting>(nameof(SysSetting) + nameof(SysSetting.SysStoreID),
                            m => m.Where(n => n.SysStoreID == storeID));
                        db.Filter<SysFile>(nameof(SysFile) + nameof(SysSetting.SysStoreID),
                            m => m.Where(n => n.SysStoreID == storeID));
                    }
                    else
                    {
                        var storeIDList = GetAllStoreIDCache(storeID, db);
                        //所有的字段加上Filter
                        if (currentStore.IsMainStore() ||
                            currentStore.EnumSysStoreType == EnumSysStoreType.子店铺)
                        {
                            EfFilterHelper.BuildFilterIntList(db, nameof(SysStore.SysStoreID), storeIDList, true, nameof(SysEmployee));

                            //员工的,因为字段没加载员工表上,所以要采用筛选数据模式
                            db.Filter<SysEmployee>(nameof(SysEmployee) + nameof(SysStore.SysStoreID),
                                m => m.Where(n =>
                                    n.SysEmployeeStoreRelation.Any(l => storeIDList.Contains(l.SysStoreID))));
                        }
                        else //if (currentStore.EnumSysStoreType == EnumSysStoreType.连锁店铺)
                        {
                            //排除掉SysDic
                            EfFilterHelper.BuildFilterInt(db, nameof(SysStore.SysStoreID), storeID,
                                true, nameof(SysDic), nameof(SysSetting), nameof(SysRolePost), nameof(SysEmployee));

                            db.Filter<SysDic>(nameof(SysDic) + nameof(SysStore.SysStoreID), m => m.Where(n => storeIDList.Contains(n.SysStoreID)));
                            db.Filter<SysSetting>(nameof(SysSetting) + nameof(SysSetting.SysStoreID), m => m.Where(n => storeIDList.Contains(n.SysStoreID)));
                            db.Filter<SysRolePost>(nameof(SysRolePost) + nameof(SysRolePost.SysStoreID),
                                m => m.Where(n => storeIDList.Contains(n.SysStoreID)));

                            //员工的,因为字段没加载员工表上,所以要采用筛选数据模式
                            db.Filter<SysEmployee>(nameof(SysEmployee) + nameof(SysStore.SysStoreID),
                                m => m.Where(n =>
                                    n.SysEmployeeStoreRelation.Any(l => l.SysStoreID == storeID)));
                        }
                    }
                }

                return db;
            }
        }

        public static DbEntities DbNoFilter
        {
            get
            {
                DbEntities db = DbEntitiesHelper.GetDbEntities(false);
                return db;
            }
        }

        #region 相关店铺ID缓存方法

        private const string CacheAllStoreID = "CacheAllStoreID";

        private static object _syncCacheAllStoreID = new object();

        /// <summary>
        /// 缓存相关店铺ID
        /// </summary>
        /// <param name="id"></param>
        /// <param name="db"></param>
        internal static List<int> SetAllStoreIDCache(int id, DbEntities db)
        {
            lock (_syncCacheAllStoreID)
            {
                var all = GetAllStoreIDCache(id);
                if (all != null) return all;
                string sql = $@"select SysStoreID--当前店铺及其所有子店铺; 1.主店铺情况
from SysStore
where SysStoreID={id} or ParentID={id}
union
select SysStoreID--当前店铺是子店铺; 得到他的上级,及其上级所有子集; 2.二级店铺情况
from SysStore
where SysStoreID in(select ParentID from SysStore where SysStoreID={id}) or ParentID in(select ParentID from SysStore where SysStoreID={id})";
                var r = db.Database.ExSqlQuery<int>(sql);
                r = r.OrderBy(m => m).ToList();
                foreach (var item in r)
                {
                    string key = CacheAllStoreID + item;
                    CacheHelper.SetRelativeCache(key, r);
                }

                return r;
            }
        }

        /// <summary>
        /// 得到所有的店铺ID
        /// </summary>
        /// <param name="id"></param>
        private static List<int> GetAllStoreIDCache(int id)
        {
            string key = CacheAllStoreID + id;
            var r = CacheHelper.GetCache(key) as List<int>;
            return r;
        }

        /// <summary>
        /// 得到所有店铺ID
        /// </summary>
        /// <param name="id"></param>
        /// <param name="db"></param>
        /// <returns></returns>
        internal static List<int> GetAllStoreIDCache(int id, DbEntities db)
        {
            string key = CacheAllStoreID + id;
            var r = CacheHelper.GetCache(key) as List<int>;
            if (r == null)
            {
                r = SetAllStoreIDCache(id, db);
            }
            return r;
        }

        /// <summary>
        /// 清除缓存
        /// </summary>
        /// <param name="id"></param>
        internal static void ClearAllStoreIDCache(int id)
        {
            var all = GetAllStoreIDCache(id);
            if (all == null) return;
            foreach (var item in all)
            {
                string key = CacheAllStoreID + item;
                CacheHelper.RemoveCache(key);
            }
        }

        #endregion

        #endregion

        #region demo演示帐号的权限验证(以前:记录原始数据的操作日志)

        /// <summary>
        /// demo演示帐号的权限验证
        /// 记录原始数据的操作日志;做为日志功能废弃了的
        /// </summary>
        /// <param name="db"></param>
        /// <param name="model"></param>
        /// <param name="enumLogType"></param>
        /// <param name="tblName"></param>
        protected string AddLog(DbEntities db, object model, EnumLogType enumLogType, string tblName = "")
        {
            var sysEmployee = CurrentEmployee;
            Type type = GetModelType(model);
            if (sysEmployee != null && sysEmployee.IsDemo)
            {
                if (enumLogType == EnumLogType.删除)
                {
                    return comLan.GetString("DemoLogin.NoDel");
                }

                if ((enumLogType == EnumLogType.登录 || enumLogType == EnumLogType.注销) == false)
                {
                    //非登录注销的
                    if (type == typeof(SysEmployee) || type == typeof(SysRolePost) || type == typeof(SysSetting) || type == typeof(SysStore))
                    {
                        return comLan.GetString("DemoLogin.NoEmployee");
                    }
                }
            }

            return null;
            try
            {
                var c = ExHttpContext.Current;
                //多线程调用添加修改等方法,c可能为null,并且c.Session会报错
                //if (c == null || c.Request == null || c.Session == null) return null;
                var request = c?.Request;
                string url = request?.ExUrl();
                //string post = c.Request.Form.ExToString();//要报错
                string post = request?.ExBodyString();
                if (string.IsNullOrEmpty(url)) url = string.Empty;
                if (string.IsNullOrEmpty(post)) post = string.Empty;
                //已经存在过url和form了,就不再添加了
                string addedKey = "getPostString" + SessionID;
                string getPostString = CacheHelper.GetCache(addedKey) as string;
                string getPost = url + post;
                if (getPostString != null && getPostString == getPost)
                {
                    return null;
                }
                CacheHelper.SetAbsoluteCache(addedKey, getPost, 10);
                SysLog log = new SysLog();
                log.GetUrl = url;
                log.PostForm = post;
                log.BeforeVal = string.Empty;
                log.PostVal = string.Empty;
                log.EnumLogType = enumLogType;
                log.CreateDate = DateTime.Now;
                log.SysEmployeeID = sysEmployee?.SysEmployeeID;
                log.UserAgent = request?.UserAgent();
                //调用IP地址
                log.IPAddress = ToolHelper.GetIpAddress();
                if (enumLogType == EnumLogType.登录)
                {
                    log.SysEmployeeID = Convert.ToInt32(model);
                    db.SysLog.Add(log);
                    //db.SaveChanges();
                    return null;
                }
                //model.ExToJson极度耗费性能,会把所有关联都给搞出来
                if (model != null)
                {
                    if (type != null)
                    {
                        if (!string.IsNullOrEmpty(tblName))
                        {
                            log.TblName = tblName;
                        }
                        else
                        {
                            log.TblName = type.FullName;
                        }
                    }

                    var ps = type.GetProperties();
                    PropertyInfo p = ps.FirstOrDefault(m =>
                        m.GetCustomAttribute<System.ComponentModel.DataAnnotations.KeyAttribute>() != null);
                    if (p == null)
                    {
                        string pk = "id";
                        var tempStr = log.TblName.ToLower();
                        p = ps.FirstOrDefault(m => m.Name.ToLower() == (tempStr + pk));
                        if (p == null)
                        {
                            p = ps.FirstOrDefault(m => m.Name.ToLower().Contains(pk));
                        }
                    }

                    if (p != null) log.TblID = Convert.ToInt32(p.GetValue(model));
                }

                db.SysLog.Add(log);
                //db.SaveChanges();
            }
            catch //(Exception e)
            {
                //Task调用新增数据库的时候,session会没有,会报错,直接忽略
                //e.ExLogError();
            }
            return null;
        }

        #endregion

        #region 当前信息

        /// <summary>
        /// 当前信息
        /// </summary>
        /// <returns></returns>
        public static string GetCurrentOther()
        {
            try
            {
                //登录信息
                string employeeInfo = string.Empty;
                string customerInfo = string.Empty;
                string customerToken = string.Empty;
                string businessEmployeeInfo = string.Empty;
                string businessEmployeeToken = string.Empty;
                string salemanInfo = string.Empty;
                string salemanToken = string.Empty;
                var c = ExHttpContext.Current;
                var s = c?.Session;
                if (c != null && s != null)
                {
                    try
                    {
                        if (SysConfig.EnumRunProject == EnumRunProject.系统后台端)
                        {
                            var employee = PcLoginedBll.CurrentEmployee;
                            if (employee != null)
                            {
                                employeeInfo = employee.SysEmployeeID + "/" + employee.SysEmployeeName + "/" +
                                               employee.SysEmployeePhone;
                            }
                        }

                        if (SysConfig.EnumRunProject == EnumRunProject.微信客户端)
                        {
                            var customerOpenID = CustomerLoginedBll.CurrentOpenID;
                            if (customerOpenID != null)
                            {
                                var customer = CustomerLoginedBll.CurrentCustomer;
                                customerInfo = customerOpenID.OpenID + "     " +
                                               (customer != null ? customer.Phone : string.Empty);
                                customerToken = customerOpenID.WechatToken;
                            }
                        }
                    }
                    catch (Exception e)
                    {
                    }
                }

                var result =
                    $"时间:{DateTime.Now.ExToLong()};项目:{SysConfig.EnumRunProject.ToString()};{(!string.IsNullOrEmpty(employeeInfo) ? ("后台端用户:" + employeeInfo + "\r\n") : string.Empty)}{(!string.IsNullOrEmpty(customerInfo) ? ("手机端用户:" + customerInfo + "     " + "Token:" + customerToken + "\r\n") : string.Empty)}";
                return result;
            }
            catch (Exception e)
            {
                return string.Empty;
            }
        }

        #endregion
    }
}
